package com.ideal.frame.nodecertificate.service;


import com.ideal.frame.jpa.DSLPageRequest;
import com.ideal.frame.jpa.JpaRepositoryImpl;
import com.ideal.frame.node.entity.NodeTb;
import com.ideal.frame.node.entity.RootNodeTb;
import com.ideal.frame.node.netty.CurrentNode;
import com.ideal.frame.node.service.NodeService;
import com.ideal.frame.node.service.RootNodeService;
import com.ideal.frame.nodecertificate.dto.CertificateForm;
import com.ideal.frame.nodecertificate.entity.NodeCertificate;
import com.ideal.frame.nodecertificate.entity.QNodeCertificate;
import com.ideal.frame.util.ShellUtil;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class NodeCertificateService {
    @PersistenceContext
    protected EntityManager entityManager;

    private JpaRepositoryImpl<NodeCertificate, Long> nodeCertificateLongJpaRepository;
    private JpaRepositoryImpl<NodeTb, Long> nodeTbLongJpaRepository;

    @Value("${node.assignKeyStore}")
    private String assignKeyStore;

    @Value("${server.ssl.trust-store}")
    private String trustStore;

    @Value("${server.ssl.key-store}")
    private String currentNodeKeyStore;

    @Value("${server.ssl.keyAlias}")
    private String currentNodeAlias;

    @Value("${node.createCerShell}")
    private String createCerShell;

    @Value("${node.createTrustStoreShell}")
    private String createTrustStoreShell;

    @Autowired
    private CurrentNode currentNode;
    @Autowired
    private RootNodeService rootNodeService;
    @Autowired
    private NodeService nodeService;

    @PostConstruct
    public void initRepo() {
        nodeCertificateLongJpaRepository = new JpaRepositoryImpl<>(NodeCertificate.class, entityManager);
        nodeTbLongJpaRepository = new JpaRepositoryImpl<>(NodeTb.class, entityManager);
    }

    QNodeCertificate qNodeCertificate = QNodeCertificate.nodeCertificate;


    public Page<NodeCertificate> getPage(CertificateForm certificateForm) {
        DSLPageRequest pageRequest = certificateForm.asDslPageRequest();
        if (certificateForm.getId() != null) {
            pageRequest.addWhere(qNodeCertificate.id.eq(certificateForm.getId()));
        }
        if (certificateForm.getName() != null) {
            pageRequest.addWhere(qNodeCertificate.name.like("%" + certificateForm.getName() + "%"));
        }
        Page<NodeCertificate> page = nodeCertificateLongJpaRepository.findAll(pageRequest);
        page.getContent().forEach(t -> {
            if (t.getNodeType() == 1) {
                t.setNode(nodeService.getById(t.getNodeId()));
            } else {
                t.setNode(rootNodeService.getById(t.getNodeId()));
            }
        });
        return page;
    }

    @Transactional(rollbackFor = Exception.class)
    public void createCer(NodeCertificate nodeCertificate) throws Exception {
        String nodeName = "", nodeIp = "";
        // 根节点
        if (nodeCertificate.getNodeType() == 0) {
            RootNodeTb nodeTb = rootNodeService.getById(nodeCertificate.getNodeId());
            nodeName = nodeTb.getNodename();
            nodeIp = nodeTb.getNodeip();
        } else {
            NodeTb nodeTb = nodeTbLongJpaRepository.findById(nodeCertificate.getNodeId()).get();
            nodeName = nodeTb.getNodename();
            nodeIp = nodeTb.getNodeip();
        }

        List<String> params = new ArrayList<>();
        params.add(assignKeyStore + nodeName + ".keystore");
        params.add(nodeIp);
        params.add(trustStore);
        ShellUtil.runShell(params, createCerShell);

        nodeCertificate.setName(nodeName + ".keystore");
        nodeCertificate.setType(KeyStore.getDefaultType());
        nodeCertificate.setCreateTime(new Date());
        nodeCertificate.setDelFlag(false);
        nodeCertificate.setCerPath(assignKeyStore + nodeName + ".keystore");
        nodeCertificateLongJpaRepository.save(nodeCertificate);
    }

    public void downLoadTrust(HttpServletResponse response) throws Exception {
        List<String> params = new ArrayList<>();
        params.add(currentNode.getIp());
        params.add(trustStore);
        params.add(currentNodeKeyStore);
        params.add(currentNodeAlias);
        ShellUtil.runShell(params, createTrustStoreShell);
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename=cacerts");
        IOUtils.copy(new FileInputStream(trustStore), response.getOutputStream());
    }

    public void downLoadCer(Long id, HttpServletResponse response) throws IOException {
        NodeCertificate nodeCertificate = nodeCertificateLongJpaRepository.findById(id).get();
        response.setCharacterEncoding("utf-8");
        String keyName = URLEncoder.encode(nodeCertificate.getName(), "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + keyName);
        IOUtils.copy(new FileInputStream(nodeCertificate.getCerPath()), response.getOutputStream());
    }

    @Transactional
    public void deleteCer(Long id) {
        nodeCertificateLongJpaRepository.updateClause().set(qNodeCertificate.delFlag, true).where(qNodeCertificate.id.eq(id)).execute();
    }
}
